use crate::tool_convert;
use crate::tool_convert::Base64;
use crate::tool_json;
use crate::tool_result::Error;
use flate2::write::{GzDecoder, GzEncoder};
use flate2::Compression;
use serde::{Deserialize, Serialize};
use std::io::prelude::*;

pub struct Gzip {}

impl Gzip {
    pub fn compress<T>(t: T) -> String
    where
        T: Serialize,
    {
        let json_str = tool_json::serialize(t).unwrap();
        let bytes = tool_convert::string_to_bytes(&json_str);
        let bytes = Gzip::compress_bytes(&bytes).unwrap();
        Base64::encode(&bytes)
    }
    pub fn decompress<T>(str: String) -> Result<T, Error>
    where
        T: for<'a> Deserialize<'a>,
    {
        let bytes = match Base64::decode(str) {
            Ok(bytes) => bytes,
            Err(e) => {
                return Err(Error::err(format!("{:?}",e.err)));
            }
        };
        let bytes = match Gzip::decompress_bytes(&bytes) {
            Ok(bytes) => bytes,
            Err(e) => {
                return Err(Error::err(e.to_string()));
            }
        };
        let json_str = tool_convert::bytes_to_string_utf8(&bytes);
        match tool_json::deserialize::<T>(json_str) {
            Ok(bytes) => Ok(bytes),
            Err(e) => {
                return Err(e);
            }
        }
    }
    pub fn compress_bytes(bytes: &[u8]) -> std::io::Result<Vec<u8>> {
        let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
        encoder.write_all(bytes)?;
        let new_bytes = encoder.finish()?;
        Ok(new_bytes)
    }
    pub fn decompress_bytes(bytes: &[u8]) -> std::io::Result<Vec<u8>> {
        let mut writer = Vec::new();
        let mut decoder = GzDecoder::new(writer);
        decoder.write_all(bytes)?;
        writer = decoder.finish()?;
        Ok(writer)
    }
}
